/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.resultset;

import java.lang.reflect.Constructor;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.loader.ResultLoader;
import org.apache.ibatis.executor.loader.ResultLoaderMap;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.result.DefaultResultContext;
import org.apache.ibatis.executor.result.DefaultResultHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.Discriminator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.reflection.MetaClass;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
/**
 * 默认Map结果处理器
 * 
 */
public class DefaultResultSetHandler implements ResultSetHandler {

	private static final Object DEFERED = new Object();
	/**
	 * 执行器
	 */
	private final Executor executor;
	/**
	 * 配置
	 */
	private final Configuration configuration;
	/**
	 * 映射的语句
	 */
	private final MappedStatement mappedStatement;
	/**
	 * Mybatis中的分页处理
	 */
	private final RowBounds rowBounds;
	/**
	 * 参数处理器
	 */
	private final ParameterHandler parameterHandler;
	/**
	 * 结果处理器
	 */
	private final ResultHandler resultHandler;
	/**
	 * 绑定的sql
	 */
	private final BoundSql boundSql;
	/**
	 * 类型处理器注册机
	 */
	private final TypeHandlerRegistry typeHandlerRegistry;
	/**
	 * 对象工厂
	 */
	private final ObjectFactory objectFactory;

	// nested resultmaps（嵌套的结果集）
	/**
	 * 此Map用来保存当前层级内部的结果对象（一对多关系的多方对象），key为combinedKey
	 */
	private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();
	/**
	 * 此Map用来保存当前层级的根对象（一对多关系中的一方对象），key为absoluteKey
	 */
	private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>();
	/**
	 * 此Map用来保存当前层级的根对象的前缀（一对多关系中的一方对象）
	 */
	private final Map<String, String> ancestorColumnPrefix = new HashMap<String, String>();

	// multiple resultsets（大量的结果集）
	/**
	 * 下一个结果集
	 */
	private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();
	/**
	 * 等待的状况
	 */
	private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();

	/**
	 * 等待的状况
	 * 
	 * @author smilesnake
	 *
	 */
	private static class PendingRelation {
		/**
		 * 元对象
		 */
		public MetaObject metaObject;
		/**
		 * 属性映射
		 */
		public ResultMapping propertyMapping;
	}

	/**
	 * DefaultResultSetHandler初始化
	 * 
	 * @param executor
	 *            执行器
	 * @param mappedStatement
	 *            映射的语句
	 * @param parameterHandler
	 *            参数处理器
	 * @param resultHandler
	 *            结果处理器
	 * @param boundSql
	 *            绑定的sql
	 * @param rowBounds
	 */
	public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement,
			ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql, RowBounds rowBounds) {
		this.executor = executor;
		this.configuration = mappedStatement.getConfiguration();
		this.mappedStatement = mappedStatement;
		this.rowBounds = rowBounds;
		this.parameterHandler = parameterHandler;
		this.boundSql = boundSql;
		this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
		this.objectFactory = configuration.getObjectFactory();
		this.resultHandler = resultHandler;
	}

	//
	// HANDLE OUTPUT PARAMETER
	//

	@Override
	public void handleOutputParameters(CallableStatement cs) throws SQLException {
		final Object parameterObject = parameterHandler.getParameterObject();
		final MetaObject metaParam = configuration.newMetaObject(parameterObject);
		final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
		// 循环处理每个参数
		for (int i = 0; i < parameterMappings.size(); i++) {
			final ParameterMapping parameterMapping = parameterMappings.get(i);
			// 只处理OUT|INOUT
			if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
				if (ResultSet.class.equals(parameterMapping.getJavaType())) {
					// 如果是ResultSet型(游标)
					// #{result, jdbcType=CURSOR, mode=OUT, javaType=ResultSet,
					// resultMap=userResultMap}
					// 先用CallableStatement.getObject取得这个游标，作为参数传进去
					handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
				} else {
					// 否则是普通型，核心就是CallableStatement.getXXX取得值
					final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
					metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
				}
			}
		}
	}

	/**
	 * 处理游标(OUT参数)
	 * 
	 * @param rs
	 *            结果Set集
	 * @param parameterMapping
	 *            参数映射
	 * @param metaParam
	 *            元参数
	 * @throws SQLException
	 */
	private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam)
			throws SQLException {
		try {
			// 得到结果ResultMap的id
			final String resultMapId = parameterMapping.getResultMapId();
			// 得到resultMap
			final ResultMap resultMap = configuration.getResultMap(resultMapId);
			// 得到默认结果处理器
			final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
			final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
			// 里面就和一般ResultSet处理没两样了
			handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
			metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
		} finally {
			// issue #228 (close resultsets)
			closeResultSet(rs);
		}
	}

	//
	// HANDLE RESULT SETS
	//
	/**
	 * 对普通查询到的结果转换
	 */
	@Override
	public List<Object> handleResultSets(Statement stmt) throws SQLException {
		ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

		final List<Object> multipleResults = new ArrayList<Object>();

		int resultSetCount = 0;
		// 获取第一个ResultSet,通常只会有一个
		ResultSetWrapper rsw = getFirstResultSet(stmt);
		// 从配置中读取对应的ResultMap，通常也只会有一个
		List<ResultMap> resultMaps = mappedStatement.getResultMaps();
		// 一般resultMaps里只有一个元素
		int resultMapCount = resultMaps.size();
		// 判断是否有resultMap,没有的话抛出异常
		validateResultMapsCount(rsw, resultMapCount);
		while (rsw != null && resultMapCount > resultSetCount) {
			ResultMap resultMap = resultMaps.get(resultSetCount);
			// 完成映射，将结果加到入multipleResults中
			handleResultSet(rsw, resultMap, multipleResults, null);
			rsw = getNextResultSet(stmt);
			cleanUpAfterHandlingResultSet();
			resultSetCount++;
		}

		String[] resultSets = mappedStatement.getResulSets();
		if (resultSets != null) {
			while (rsw != null && resultSetCount < resultSets.length) {
				ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
				if (parentMapping != null) {
					String nestedResultMapId = parentMapping.getNestedResultMapId();
					ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
					handleResultSet(rsw, resultMap, null, parentMapping);
				}
				rsw = getNextResultSet(stmt);
				cleanUpAfterHandlingResultSet();
				resultSetCount++;
			}
		}
		// 如果只有一个映射，返回第一个
		return collapseSingleResultList(multipleResults);
	}

	/**
	 * 得到第一个结果集
	 * 
	 * @param stmt
	 *            语句
	 * @return
	 * @throws SQLException
	 */
	private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
		ResultSet rs = stmt.getResultSet();
		// HSQLDB2.1特殊情况处理
		while (rs == null) {
			// move forward to get the first resultset in case the driver
			// doesn't return the resultset as the first result (HSQLDB 2.1)
			if (stmt.getMoreResults()) {
				rs = stmt.getResultSet();
			} else {
				if (stmt.getUpdateCount() == -1) {
					// no more results. Must be no resultset
					break;
				}
			}
		}
		return rs != null ? new ResultSetWrapper(rs, configuration) : null;
	}

	/**
	 * 得到下一个结果集
	 * 
	 * @param stmt
	 *            语句
	 * @return
	 * @throws SQLException
	 */
	private ResultSetWrapper getNextResultSet(Statement stmt) throws SQLException {
		// Making this method tolerant of bad JDBC drivers
		try {
			if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
				// Crazy Standard JDBC way of determining if there are more
				// results
				if (!((!stmt.getMoreResults()) && (stmt.getUpdateCount() == -1))) {
					ResultSet rs = stmt.getResultSet();
					return rs != null ? new ResultSetWrapper(rs, configuration) : null;
				}
			}
		} catch (Exception e) {
			// Intentionally ignored.
		}
		return null;
	}

	/**
	 * 关闭结果集
	 * 
	 * @param rs
	 *            结果集
	 */
	private void closeResultSet(ResultSet rs) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			// ignore
		}
	}

	/**
	 * 清除自上而下的结果集处理器
	 */
	private void cleanUpAfterHandlingResultSet() {
		nestedResultObjects.clear();
		ancestorColumnPrefix.clear();
	}

	/**
	 * 判断是否有resultMap,没有的话抛出异常
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMapCount
	 *            结果集数量
	 */
	private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
		if (rsw != null && resultMapCount < 1) {
			throw new ExecutorException(
					"A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
							+ "'.  It's likely that neither a Result Type nor a Result Map was specified.");
		}
	}

	/**
	 * 处理结果集
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param multipleResults
	 *            结果集
	 * @param parentMapping
	 *            父类结果映射
	 * @throws SQLException
	 */
	private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
			ResultMapping parentMapping) throws SQLException {
		try {
			if (parentMapping != null) {
				// 子映射
				handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
			} else {
				// 一般情况resultHandler都为空,见ResultHandler.NO_RESULT_HANDLER
				if (resultHandler == null) {
					// 如果没有resultHandler
					// 新建DefaultResultHandler
					DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
					// 调用自己的handleRowValues
					// 生成对象，并加到defaultResultHandler.resultList集合中
					handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
					// 得到记录的list
					// 将结果加入multipleResults中
					multipleResults.add(defaultResultHandler.getResultList());
				} else {
					// 如果有resultHandler
					handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
				}
			}
		} finally {
			// 最后别忘了关闭结果集，这个居然出bug了
			// issue #228 (close resultsets)
			closeResultSet(rsw.getResultSet());
		}
	}

	/**
	 * 折叠常用的结果集
	 * 
	 * @param multipleResults
	 *            结果集
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<Object> collapseSingleResultList(List<Object> multipleResults) {
		return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
	}

	//
	// HANDLE ROWS FOR SIMPLE RESULTMAP
	//
	/**
	 * 处理行的值
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param resultHandler
	 *            结果处理器
	 * @param rowBounds
	 *            分页用，记录限制
	 * @param parentMapping
	 *            父类结果映射
	 * @throws SQLException
	 */
	private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler,
			RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
		if (resultMap.hasNestedResultMaps()) {
			// 有子映射或内映射的情况
			ensureNoRowBounds();
			checkResultHandler();
			handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
		} else {
			// 没有子映射或内映射
			handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
		}
	}

	/**
	 * 确保没有行超过界定
	 */
	private void ensureNoRowBounds() {
		if (configuration.isSafeRowBoundsEnabled() && rowBounds != null
				&& (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {
			throw new ExecutorException(
					"Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. "
							+ "Use safeRowBoundsEnabled=false setting to bypass this check.");
		}
	}

	/**
	 * 检查结果处理器
	 */
	protected void checkResultHandler() {
		if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {
			throw new ExecutorException(
					"Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "
							+ "Use safeResultHandlerEnabled=false setting to bypass this check "
							+ "or ensure your statement returns ordered data and set resultOrdered=true on it.");
		}
	}

	/**
	 * 简单映射 处理行值----简单的结果集
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param resultHandler
	 *            结果处理器
	 * @param rowBounds
	 *            分页用，记录限制
	 * @param parentMapping
	 *            父类结果映射
	 * @throws SQLException
	 */
	private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
			ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
		DefaultResultContext resultContext = new DefaultResultContext();
		skipRows(rsw.getResultSet(), rowBounds);
		while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
			// discriminator的处理,可以根据条件选择不同的映射
			ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
			// 真正从ResultSet中映射出一个对象
			Object rowValue = getRowValue(rsw, discriminatedResultMap);
			// 加入resultHandler.resultList中
			storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
		}
	}

	/**
	 * 对象仓库
	 * 
	 * @param resultHandler
	 *            结果处理器
	 * @param resultContext
	 *            默认结果上下文
	 * @param rowValue
	 *            行值
	 * @param parentMapping
	 *            父类结果映射
	 * @param rs
	 *            结果集
	 * @throws SQLException
	 */
	private void storeObject(ResultHandler resultHandler, DefaultResultContext resultContext, Object rowValue,
			ResultMapping parentMapping, ResultSet rs) throws SQLException {
		if (parentMapping != null) {
			linkToParents(rs, parentMapping, rowValue);
		} else {
			callResultHandler(resultHandler, resultContext, rowValue);
		}
	}

	/**
	 * 存储过程结果处理
	 * 
	 * @param resultHandler
	 *            结果处理器
	 * @param resultContext
	 *            默认结果上下文
	 * @param rowValue
	 *            行值
	 */
	private void callResultHandler(ResultHandler resultHandler, DefaultResultContext resultContext, Object rowValue) {
		resultContext.nextResultObject(rowValue);
		resultHandler.handleResult(resultContext);
	}

	/**
	 * 是否可能处理更多的行
	 * 
	 * @param context
	 *            结果上下文
	 * @param rowBounds
	 *            分页用，记录限制
	 * @return
	 * @throws SQLException
	 */
	private boolean shouldProcessMoreRows(ResultContext context, RowBounds rowBounds) throws SQLException {
		return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
	}

	/**
	 * 跳过行
	 * 
	 * @param rs
	 *            结果集
	 * @param rowBounds
	 *            分页用，记录限制
	 * @throws SQLException
	 */
	private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
		if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
			if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
				rs.absolute(rowBounds.getOffset());
			}
		} else {
			for (int i = 0; i < rowBounds.getOffset(); i++) {
				rs.next();
			}
		}
	}

	//
	// GET VALUE FROM ROW FOR SIMPLE RESULT MAP
	//

	/**
	 * 核心，取得一行的值(简单的结果集，没有内映射)
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            Set结果集包装器
	 * @return
	 * @throws SQLException
	 */
	private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
		// 实例化ResultLoaderMap(延迟加载器)
		final ResultLoaderMap lazyLoader = new ResultLoaderMap();
		// 调用自己的createResultObject,内部就是new一个对象(如果是简单类型，new完也把值赋进去)
		// 实例化一个对象,类型为resultMap.getType(),最终调用了ObjectFactory.create()方法
		Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
		if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
			// 一般不是简单类型不会有typehandler,这个if会进来
			// 设置对象属性
			final MetaObject metaObject = configuration.newMetaObject(resultObject);
			boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
			if (shouldApplyAutomaticMappings(resultMap, false)) {
				// 这里把每个列的值都赋到相应的字段里去了
				// 自动映射,结果集中有的column，但resultMap中并没有配置
				foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
			}
			// 映射result节点
			foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
			foundValues = lazyLoader.size() > 0 || foundValues;
			resultObject = foundValues ? resultObject : null;
			return resultObject;
		}
		return resultObject;
	}

	/**
	 * 判断是否可能使用了自动映射
	 * 
	 * @param resultMap
	 *            结果映射
	 * @param isNested
	 *            是否为内嵌
	 * @return
	 */
	private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
		if (resultMap.getAutoMapping() != null) {
			return resultMap.getAutoMapping();
		} else {
			if (isNested) {
				return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
			} else {
				return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
			}
		}
	}

	//
	// PROPERTY MAPPINGS
	//
	/**
	 * 应用属性映射
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param metaObject
	 *            元对象
	 * @param lazyLoader
	 *            结果延迟加载器映射
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
			ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
		final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
		boolean foundValues = false;
		// 获取需要映射的ResultMapping
		final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
		for (ResultMapping propertyMapping : propertyMappings) {
			String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
			if (propertyMapping.getNestedResultMapId() != null) {
				// the user added a column attribute to a nested result map,
				// ignore it
				column = null;
			}
			if (propertyMapping.isCompositeResult()
					|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
					|| propertyMapping.getResultSet() != null) {
				// 在结果中的获取对应的值
				Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader,
						columnPrefix);
				// issue #541 make property optional
				final String property = propertyMapping.getProperty();
				// issue #377, call setter on nulls
				if (value != DEFERED && property != null && (value != null || (configuration.isCallSettersOnNulls()
						&& !metaObject.getSetterType(property).isPrimitive()))) {
					// 设置属性
					metaObject.setValue(property, value);
				}
				if (value != null || value == DEFERED) {
					foundValues = true;
				}
			}
		}
		return foundValues;
	}

	/**
	 * 得到属性映射的值
	 * 
	 * @param rs
	 *            结果集
	 * @param metaResultObject
	 *            元结果对象
	 * @param propertyMapping
	 *            属性映射
	 * @param lazyLoader
	 *            懒加载
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping,
			ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
		if (propertyMapping.getNestedQueryId() != null) {
			// 子查询，这里就是会产生N+1次查询的地方，每个记录都会再执行一个子查询。子查询的过程这里就不在讨论了。
			return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
		} else if (propertyMapping.getResultSet() != null) {
			addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO
																			// is
																			// that
																			// OK?
			return DEFERED;
		} else {
			final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
			final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
			// 直接从结果集里获取。
			return typeHandler.getResult(rs, column);
		}
	}

	/**
	 * 应用自动映射
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param metaObject
	 *            元对象
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
			String columnPrefix) throws SQLException {
		// 获取结果集中在resultMap中没有配置的列名
		// 如果resultMap中只设置了resultType="java.util.HashMap"的话，全都会在这里完成映射
		final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
		boolean foundValues = false;
		for (String columnName : unmappedColumnNames) {
			// 属性名就是列名
			String propertyName = columnName;
			if (columnPrefix != null && !columnPrefix.isEmpty()) {
				// When columnPrefix is specified,
				// ignore columns without the prefix.
				if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
					propertyName = columnName.substring(columnPrefix.length());
				} else {
					continue;
				}
			}
			// 是否有对应的属性
			final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
			// 是否有对应的set方法
			if (property != null && metaObject.hasSetter(property)) {
				final Class<?> propertyType = metaObject.getSetterType(property);
				if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
					final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
					// 巧妙的用TypeHandler取得结果
					final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
					// issue #377, call setter on nulls
					if (value != null || configuration.isCallSettersOnNulls()) {
						if (value != null || !propertyType.isPrimitive()) {
							// 然后巧妙的用反射来设置到对象
							metaObject.setValue(property, value);
						}
						foundValues = true;
					}
				}
			}
		}
		return foundValues;
	}

	// MULTIPLE RESULT SETS
	/**
	 * 链接到上一级 ---即父级
	 * 
	 * @param rs
	 *            结果集
	 * @param parentMapping
	 *            父级映射
	 * @param rowValue
	 *            行值
	 * @throws SQLException
	 */
	private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
		CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(),
				parentMapping.getForeignColumn());
		// 得到父级
		List<PendingRelation> parents = pendingRelations.get(parentKey);
		if (parents != null) {
			// 遍历
			for (PendingRelation parent : parents) {
				if (parent != null) {
					final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(parent.propertyMapping,
							parent.metaObject);
					if (rowValue != null) {
						if (collectionProperty != null) {
							final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
							// 添加元素
							targetMetaObject.add(rowValue);
						} else {
							// 添加元素
							parent.metaObject.setValue(parent.propertyMapping.getProperty(), rowValue);
						}
					}
				}
			}
		}
	}

	/**
	 * 如果匹配就实例化收集属性
	 * 
	 * @param resultMapping
	 *            结果映射
	 * @param metaObject
	 *            元对象
	 * @return
	 */
	private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
		// 得到结果映射的属性名
		final String propertyName = resultMapping.getProperty();
		// 得到属性值
		Object propertyValue = metaObject.getValue(propertyName);
		if (propertyValue == null) {
			// 得到映射的结果类型
			Class<?> type = resultMapping.getJavaType();
			if (type == null) {
				// 得到映射的结果类型的setter的类型列表
				type = metaObject.getSetterType(propertyName);
			}
			try {
				// 判断是否为集合
				if (objectFactory.isCollection(type)) {
					// 创建对象
					propertyValue = objectFactory.create(type);
					// 设置值
					metaObject.setValue(propertyName, propertyValue);
					return propertyValue;
				}
			} catch (Exception e) {
				throw new ExecutorException("Error instantiating collection property for result '"
						+ resultMapping.getProperty() + "'.  Cause: " + e, e);
			}
		} else if (objectFactory.isCollection(propertyValue.getClass())) {
			return propertyValue;
		}
		return null;
	}

	/**
	 * 添加未定的子集
	 * 
	 * @param rs
	 *            结果集
	 * @param metaResultObject
	 *            元结果对象
	 * @param parentMapping
	 *            父级映射
	 * @throws SQLException
	 */
	private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping)
			throws SQLException {
		CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(),
				parentMapping.getColumn());
		PendingRelation deferLoad = new PendingRelation();
		deferLoad.metaObject = metaResultObject;
		deferLoad.propertyMapping = parentMapping;
		List<PendingRelation> relations = pendingRelations.get(cacheKey);
		// issue #255
		if (relations == null) {
			relations = new ArrayList<DefaultResultSetHandler.PendingRelation>();
			pendingRelations.put(cacheKey, relations);
		}
		relations.add(deferLoad);
		ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
		if (previous == null) {
			nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
		} else {
			if (!previous.equals(parentMapping)) {
				throw new ExecutorException("Two different properties are mapped to the same resultSet");
			}
		}
	}

	/**
	 * 为大量的结果创建key值
	 * 
	 * @param rs
	 *            结果集
	 * @param resultMapping
	 *            结果映射
	 * @param names
	 *            名字
	 * @param columns
	 *            列
	 * @return
	 * @throws SQLException
	 */
	private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names,
			String columns) throws SQLException {
		CacheKey cacheKey = new CacheKey();
		cacheKey.update(resultMapping);
		if (columns != null && names != null) {
			String[] columnsArray = columns.split(",");
			String[] namesArray = names.split(",");
			for (int i = 0; i < columnsArray.length; i++) {
				Object value = rs.getString(columnsArray[i]);
				if (value != null) {
					cacheKey.update(namesArray[i]);
					cacheKey.update(value);
				}
			}
		}
		return cacheKey;
	}

	//
	// INSTANTIATION & CONSTRUCTOR MAPPING
	//
	/**
	 * 构造方法实例化对象
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param lazyLoader
	 *            结果延迟加载器映射
	 * @param columnPrefix
	 *            列的前缀
	 * @return
	 * @throws SQLException
	 */
	private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader,
			String columnPrefix) throws SQLException {
		// 构造方法中的参数类型
		final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
		// 构造方法中具体值
		final List<Object> constructorArgs = new ArrayList<Object>();
		// 根据构造方法生成对象
		final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs,
				columnPrefix);
		if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
			final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
			for (ResultMapping propertyMapping : propertyMappings) {
				// issue gcode #109 && issue #149
				if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
					// TODO 使用代理(cglib/javaassist)
					return configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration,
							objectFactory, constructorArgTypes, constructorArgs);
				}
			}
		}
		return resultObject;
	}

	/**
	 * 创建结果对象
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param constructorArgTypes
	 *            构造函数的参数类型
	 * @param constructorArgs
	 *            构造函数的参数值
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,
			List<Object> constructorArgs, String columnPrefix) throws SQLException {
		// 得到result type
		final Class<?> resultType = resultMap.getType();
		// resultMap配置中的construnctor节点
		final MetaClass metaType = MetaClass.forClass(resultType);
		final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
		if (typeHandlerRegistry.hasTypeHandler(resultType)) {
			// 基本型
			return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
		} else if (!constructorMappings.isEmpty()) {
			// 有参数的构造函数
			// construnctor节点有配置
			return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes,
					constructorArgs, columnPrefix);
		} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
			// 普通bean类型,
			// construnctor节点没有配置，调用无参的构造方法
			return objectFactory.create(resultType);
		} else if (shouldApplyAutomaticMappings(resultMap, false)) {
			// 自动映射
			return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
		}
		throw new ExecutorException("Do not know how to create an instance of " + resultType);
	}

	/**
	 * 创建参数化结果集
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultType
	 *            结果类型
	 * @param constructorMappings
	 *            构造方法映射
	 * @param constructorArgTypes
	 *            构造函数的参数类型
	 * @param constructorArgs
	 *            构造函数的参数值
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType,
			List<ResultMapping> constructorMappings, List<Class<?>> constructorArgTypes, List<Object> constructorArgs,
			String columnPrefix) throws SQLException {
		boolean foundValues = false;
		for (ResultMapping constructorMapping : constructorMappings) {
			final Class<?> parameterType = constructorMapping.getJavaType();
			final String column = constructorMapping.getColumn();
			final Object value;
			// 取出参数类型和具体的值
			if (constructorMapping.getNestedQueryId() != null) {
				value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
			} else if (constructorMapping.getNestedResultMapId() != null) {
				final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
				value = getRowValue(rsw, resultMap);
			} else {
				final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
				value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
			}
			constructorArgTypes.add(parameterType);
			constructorArgs.add(value);
			foundValues = value != null || foundValues;
		}
		// 创建对象
		return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
	}

	/**
	 * 创建构造函数签名
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultType
	 *            结果类型
	 * @param constructorArgTypes
	 *            构造函数的参数类型
	 * @param constructorArgs
	 *            构造函数的参数值
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType,
			List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException {
		for (Constructor<?> constructor : resultType.getDeclaredConstructors()) {
			if (typeNames(constructor.getParameterTypes()).equals(rsw.getClassNames())) {
				boolean foundValues = false;
				for (int i = 0; i < constructor.getParameterTypes().length; i++) {
					Class<?> parameterType = constructor.getParameterTypes()[i];
					String columnName = rsw.getColumnNames().get(i);
					TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
					Object value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(columnName, columnPrefix));
					constructorArgTypes.add(parameterType);
					constructorArgs.add(value);
					foundValues = value != null || foundValues;
				}
				// 上面是构造函数创建对象，下面是对象工厂来创建
				return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
			}
		}
		throw new ExecutorException(
				"No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
	}

	/**
	 * 类型名称
	 * 
	 * @param parameterTypes
	 *            参数类型
	 * @return
	 */
	private List<String> typeNames(Class<?>[] parameterTypes) {
		List<String> names = new ArrayList<String>();
		for (Class<?> type : parameterTypes) {
			names.add(type.getName());
		}
		return names;
	}

	/**
	 * 创建原始的结果对象
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	// 简单类型走这里
	private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix)
			throws SQLException {
		final Class<?> resultType = resultMap.getType();
		final String columnName;
		if (!resultMap.getResultMappings().isEmpty()) {
			final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
			final ResultMapping mapping = resultMappingList.get(0);
			columnName = prependPrefix(mapping.getColumn(), columnPrefix);
		} else {
			// 因为只有1列，所以取得这一列的名字
			columnName = rsw.getColumnNames().get(0);
		}
		final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
		return typeHandler.getResult(rsw.getResultSet(), columnName);
	}

	//
	// NESTED QUERY(内嵌查询)
	//
	/**
	 * 得到内嵌查询构造方法的值
	 * 
	 * @param rs
	 *            结果集
	 * @param constructorMapping
	 *            构造器映射
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix)
			throws SQLException {
		final String nestedQueryId = constructorMapping.getNestedQueryId();
		final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
		final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
		final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping,
				nestedQueryParameterType, columnPrefix);
		Object value = null;
		if (nestedQueryParameterObject != null) {
			final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
			final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT,
					nestedBoundSql);
			final Class<?> targetType = constructorMapping.getJavaType();
			final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery,
					nestedQueryParameterObject, targetType, key, nestedBoundSql);
			value = resultLoader.loadResult();
		}
		return value;
	}

	/**
	 * 得到嵌套查询映射的值
	 * 
	 * @param rs
	 *            结果集
	 * @param metaResultObject
	 *            元结果对象
	 * @param propertyMapping
	 *            属性映射
	 * @param lazyLoader
	 *            结果延迟加载器映射
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping,
			ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
		final String nestedQueryId = propertyMapping.getNestedQueryId();
		final String property = propertyMapping.getProperty();
		final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
		final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
		final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping,
				nestedQueryParameterType, columnPrefix);
		Object value = null;
		if (nestedQueryParameterObject != null) {
			final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
			final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT,
					nestedBoundSql);
			final Class<?> targetType = propertyMapping.getJavaType();
			if (executor.isCached(nestedQuery, key)) {
				// 如果已经有一级缓存了，则延迟加载(实际上deferLoad方法中可以看到则是立即加载)
				executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
				value = DEFERED;
			} else {
				// 否则lazyLoader.addLoader 需要延迟加载则addLoader
				// 或者ResultLoader.loadResult 不需要延迟加载则立即加载
				final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery,
						nestedQueryParameterObject, targetType, key, nestedBoundSql);
				if (propertyMapping.isLazy()) {
					lazyLoader.addLoader(property, metaResultObject, resultLoader);
					value = DEFERED;
				} else {
					value = resultLoader.loadResult();
				}
			}
		}
		return value;
	}

	/**
	 * 预处理参数----内嵌查询
	 * 
	 * @param rs
	 *            结果集
	 * @param resultMapping
	 *            结果映射
	 * @param parameterType
	 *            参数类型
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType,
			String columnPrefix) throws SQLException {
		if (resultMapping.isCompositeResult()) {
			return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
		} else {
			return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
		}
	}

	/**
	 * 预处理常用的key参数
	 * 
	 * @param rs
	 *            结果集
	 * @param resultMapping
	 *            结果映射
	 * @param parameterType
	 *            参数类型
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType,
			String columnPrefix) throws SQLException {
		final TypeHandler<?> typeHandler;
		if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
			typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
		} else {
			typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
		}
		return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
	}

	/**
	 * 预处理混合的key参数
	 * 
	 * @param rs
	 *            结果集
	 * @param resultMapping
	 *            结果映射
	 * @param parameterType
	 *            参数类型
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType,
			String columnPrefix) throws SQLException {
		final Object parameterObject = instantiateParameterObject(parameterType);
		final MetaObject metaObject = configuration.newMetaObject(parameterObject);
		boolean foundValues = false;
		for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
			final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
			final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
			final Object propValue = typeHandler.getResult(rs,
					prependPrefix(innerResultMapping.getColumn(), columnPrefix));
			// issue #353 & #560 do not execute nested query if key is null
			if (propValue != null) {
				metaObject.setValue(innerResultMapping.getProperty(), propValue);
				foundValues = true;
			}
		}
		return foundValues ? parameterObject : null;
	}

	/**
	 * 实例化参数对象
	 * 
	 * @param parameterType
	 *            参数类型
	 * @return
	 */
	private Object instantiateParameterObject(Class<?> parameterType) {
		if (parameterType == null) {
			return new HashMap<Object, Object>();
		} else {
			return objectFactory.create(parameterType);
		}
	}

	//
	// DISCRIMINATOR
	//
	/**
	 * 解析区分结果集
	 * 
	 * @param rs
	 * @param resultMap
	 * @param columnPrefix
	 * @return
	 * @throws SQLException
	 */
	public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix)
			throws SQLException {
		Set<String> pastDiscriminators = new HashSet<String>();
		Discriminator discriminator = resultMap.getDiscriminator();
		while (discriminator != null) {
			final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
			final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
			if (configuration.hasResultMap(discriminatedMapId)) {
				resultMap = configuration.getResultMap(discriminatedMapId);
				Discriminator lastDiscriminator = discriminator;
				discriminator = resultMap.getDiscriminator();
				if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
					break;
				}
			} else {
				break;
			}
		}
		return resultMap;
	}

	/**
	 * 得到鉴定器的值
	 * 
	 * @param rs
	 *            结果集
	 * @param discriminator
	 *            鉴定器
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix)
			throws SQLException {
		final ResultMapping resultMapping = discriminator.getResultMapping();
		final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
		return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
	}

	/**
	 * 预置前缀
	 * 
	 * @param columnName
	 *            列名
	 * @param prefix
	 *            前缀
	 * @return
	 */
	private String prependPrefix(String columnName, String prefix) {
		if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
			return columnName;
		}
		return prefix + columnName;
	}

	//
	// HANDLE NESTED RESULT MAPS 处理嵌套结果映射 复杂映射(内映射)
	//

	// 示例<resultMap type="com.ashan.mybatis.User" id="detailUserResultMap"><!--
	// 整个resultMap会被解析成一个ResultMap对应 -->
	// <constructor>
	// <idArg column="user_id" javaType="String"/><!--
	// idArg会被解析成一个resultMapping对象 -->
	// <arg column="user_name" javaType="String"/><!-- resultMapping对象 -->
	// </constructor>
	//
	// <result property="svcnum" column="svc_num" /> <!-- resultMapping对象 -->
	//
	// <association property="cust" javaType="com.ashan.mybatis.Cust"> <!--
	// resultMapping对象 这个resultMapping对象指向了另一个ResultMap-->
	// <id property="id" column="cust_id"/>
	// <result property="custname" column="cust_name"/>
	// <result property="certNo" column="cert_no"/>
	// </association>
	//
	// <collection property="accts" ofType="com.ashan.mybatis.Acct">
	// <id property="id" column="acct_id" />
	// <result property="payName" column="pay_name"/>
	// <result property="bankNo" column="bank_no"/>
	// </collection>
	//
	// </resultMap>
	/**
	 * 处理行值-----嵌套结果集
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param resultHandler
	 *            结果处理器
	 * @param rowBounds
	 *            分页用，记录限制
	 * @param parentMapping
	 *            父级映射
	 * @throws SQLException
	 */
	private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap,
			ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
		// 创建默认结果上下文
		final DefaultResultContext resultContext = new DefaultResultContext();
		// 跳过rowBounds指定offset行偏移量
		skipRows(rsw.getResultSet(), rowBounds);
		Object rowValue = null;
		// 如何定义应该处理：上下文没有主动停止，结果集还有记录，且上下文中结果对象数量不足时，应该继续处理
		while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
			// 开始处理一行新的结果集记录
			// 解决鉴别过的结果映射，逻辑如下：
			// 获取结果映射中的鉴别器，通过鉴别指定字段通过配置对象获取对应的另一个结果映射，循环往复，
			// 直到找不到鉴别器为止，返回最终的结果映射
			final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
			// 为这行记录生成一个key,createRowKey方法会利用idResultMapping(即idArg,和id节点)和resultMap的id来生成key
			// 例子中第1、2、4条记录生成的key都是一样的,大概内容为detailUserResultMap:user_01
			// 第3条记录生成的key大概内容为detailUserResultMap:user_02
			final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
			// nestedResultObjects是一个HashMap对象，在映射过程中所有生成的映射对象(包括内映射对象)，都会生成一个key并保存在这里。
			// 例子中生成映射对象有三类：User,Cust,Acct
			// 缓存中获取结果对象
			Object partialObject = nestedResultObjects.get(rowKey);
			// issue #577 && #542
			// 如果是处理第1、3条记录，这里的parialObject为null值
			// 如果是处理第2、4条记录，这里的parialObject不为null
			if (mappedStatement.isResultOrdered()) {
				if (partialObject == null && rowValue != null) {
					nestedResultObjects.clear();
					// 保存结果对象
					storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
				}
				rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
			} else {
				// 这个方法把结果集的记录映射成java对象
				// 处理第一条记录时，rowValue是新生成的User对象(user_01)其中属性cust为cust_01,accts里只有一个acct_01
				// 处理第二条记录时，rowValue对象就是第一条记录生成里的User对象，不过这时accts里多了一条acct_02
				// 处理第三条记录时，rowValue为新生成的User对象(user_02)，cust属性为cust_01,accts只有一个acct_03
				// 处理第四条记录时，rowValue对象就是第一条记录生成里的User对象，这时accts里又多了一条acct_04
				// 获取行值
				rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
				// 只有第一条记录和第三条记录partialObject才会为null
				if (partialObject == null) {
					// 把User对象加入到resultHandler.resultList中，这里也可以看出，虽然有四条记录，但只会被映射成两个User对象
					storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
				}
			}
		}
		if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
			storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
		}
	}

	//
	// GET VALUE FROM ROW FOR NESTED RESULT MAP
	//
	/**
	 * 为嵌套结果映射从行获取值
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param combinedKey
	 *            缓存key
	 * @param absoluteKey
	 *            绝对key
	 * @param columnPrefix
	 *            列前缀
	 * @param partialObject
	 *            部分对象
	 * @return
	 * @throws SQLException
	 */
	private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey,
			String columnPrefix, Object partialObject) throws SQLException {
		final String resultMapId = resultMap.getId();
		Object resultObject = partialObject;
		// 第一和第三条记录时，partialObject为null, resultObject也为null
		if (resultObject != null) {
			// 处理第二、四条记录里会执行这里
			final MetaObject metaObject = configuration.newMetaObject(resultObject);
			putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
			// 直接调用内映射，即设置处理cust和accts，例子中主要是加入一个acct,因为cust只有一个，在user对象创建里就会被创建
			applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
			ancestorObjects.remove(absoluteKey);
		} else {
			// 处理第一、三条记录里会执行这里,说明需要创建一个新的User对象
			final ResultLoaderMap lazyLoader = new ResultLoaderMap();
			// 创建一个user对象，跟简单映射的处理方式一样
			resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
			if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
				final MetaObject metaObject = configuration.newMetaObject(resultObject);
				boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
				if (shouldApplyAutomaticMappings(resultMap, true)) {
					// 自动映射，跟简单映射的处理方式一样,跟简单映射的处理方式一样,例子中不会执行这一步
					foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
				}
				// 映射reulst节点，跟简单映射的处理方式一样,跟简单映射的处理方式一样 ,例子中主要映射svc_num
				foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix)
						|| foundValues;
				putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
				// 调用内映射，即生成cust和acct对象并设置到User对象中
				foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true)
						|| foundValues;
				ancestorObjects.remove(absoluteKey);
				foundValues = lazyLoader.size() > 0 || foundValues;
				resultObject = foundValues ? resultObject : null;
			}
			// 注意这里，生成User对象里combinedKey就是User对象的key,将新创建的两个User对象加入nestedResultObjects中，以便后续处理使用，在处理第二、四条记录里就可以使用对应的User对象了。
			if (combinedKey != CacheKey.NULL_CACHE_KEY) {
				nestedResultObjects.put(combinedKey, resultObject);
			}
		}
		return resultObject;
	}

	/**
	 * 放置根对象
	 * 
	 * @param rowKey
	 *            行key
	 * @param resultObject
	 *            结果对象
	 * @param resultMapId
	 *            结果MapId
	 * @param columnPrefix
	 *            列前缀
	 */
	private void putAncestor(CacheKey rowKey, Object resultObject, String resultMapId, String columnPrefix) {
		if (!ancestorColumnPrefix.containsKey(resultMapId)) {
			ancestorColumnPrefix.put(resultMapId, columnPrefix);
		}
		ancestorObjects.put(rowKey, resultObject);
	}

	//
	// NESTED RESULT MAP (JOIN MAPPING)
	//
	/**
	 * 处理内映射，生成内映射对象，并加入到上层对象中。这里主要根据例子分析Cust对象的生成，上层对象为User
	 * 
	 * @param rsw
	 *            Set结果集包装器
	 * @param resultMap
	 *            结果映射
	 * @param metaObject
	 *            元对象,
	 * @param parentPrefix
	 *            父级前缀
	 * @param parentRowKey
	 *            父级行key
	 * @param newObject
	 * @return
	 */
	private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
			String parentPrefix, CacheKey parentRowKey, boolean newObject) {
		boolean foundValues = false;
		for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
			final String nestedResultMapId = resultMapping.getNestedResultMapId();
			if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
				// resultMap中的collection,association节点都会被生成一个nestedResultMap,这里分析Cust对象，也就是association
				try {
					final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
					// 获取内映射的ResultMap
					final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId,
							columnPrefix);
					CacheKey rowKey = null;
					Object ancestorObject = null;
					if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
						// 第二、三、四记录时会执行,ancestorColumnPrefi也是一个HashMap,保存的是什么内容下面再看
						// 第一条记录时，肯定不会有这个对应关系
						rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
						// 这个ancestorObjects是一个HashMap跟名字一样只会保存原始对应，也就是上层对象，这里cust和acct对象是最下层的对象了。也就是说cust和acct没有内映射了
						// 所以例子中ancestorObjects只会保留User对象
						ancestorObject = ancestorObjects.get(rowKey);
					}
					if (ancestorObject != null) {
						if (newObject) {
							metaObject.setValue(resultMapping.getProperty(), ancestorObject);
						}
					} else {
						// 映射四条记录的Cust对应都会执行这里
						// 这里是生成内映射Cust的key,大概是这样的:Cust:cust_01
						rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
						// 这里的combineKeys是跟上层对象组合成的一个key
						// parentRowKey为上层对象(User对象)的key,第一、二、四条记录为user_01,第三条记录为user_02
						// 这样combineKey值大概为:第一、二、四条记录为user_01:cust_01,第三条记录为user_02:cust_01
						final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
						// 从nestedResultObjects获取
						// 第一、三条记录rowValue是为null的,第二、四条记录与第一条记录的combinedKey一样，所以rowValue的值不一样
						Object rowValue = nestedResultObjects.get(combinedKey);
						boolean knownValue = (rowValue != null);
						// 检查要映射的对象是否为Collection类型，这里是Cust类型，collectionProperty为null
						final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping,
								metaObject);
						if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
							// 生成Cust对象
							// 注意入参的rowValue，第一、三条记录为null
							rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
							if (rowValue != null && !knownValue) {
								// 第一、三条记录时才会执行这里，第二、四条记录用的是第一条中的Cust对象，不用重复设置
								if (collectionProperty != null) {
									// User.cust属性不是集合，不会执行这里
									final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
									targetMetaObject.add(rowValue);
								} else {
									// 将生成的Cust对象设置到User对象中
									metaObject.setValue(resultMapping.getProperty(), rowValue);
								}
								foundValues = true;
							}
						}
					}
				} catch (SQLException e) {
					throw new ExecutorException("Error getting nested result map values for '"
							+ resultMapping.getProperty() + "'.  Cause: " + e, e);
				}
			}
		}
		return foundValues;
	}

	/**
	 * 得到父类前缀
	 * 
	 * @param parentPrefix
	 *            父级前缀
	 * @param resultMapping
	 *            结果映射
	 * @return
	 */
	private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
		final StringBuilder columnPrefixBuilder = new StringBuilder();
		if (parentPrefix != null) {
			columnPrefixBuilder.append(parentPrefix);
		}
		if (resultMapping.getColumnPrefix() != null) {
			columnPrefixBuilder.append(resultMapping.getColumnPrefix());
		}
		return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
	}

	/**
	 * 判断任何不为空的列的hash值
	 * 
	 * @param resultMapping
	 *            结果映射
	 * @param columnPrefix
	 *            列前缀
	 * @param rs
	 *            结果集
	 * @return
	 * @throws SQLException
	 */
	private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSet rs)
			throws SQLException {
		Set<String> notNullColumns = resultMapping.getNotNullColumns();
		boolean anyNotNullColumnHasValue = true;
		if (notNullColumns != null && !notNullColumns.isEmpty()) {
			anyNotNullColumnHasValue = false;
			for (String column : notNullColumns) {
				rs.getObject(prependPrefix(column, columnPrefix));
				if (!rs.wasNull()) {
					anyNotNullColumnHasValue = true;
					break;
				}
			}
		}
		return anyNotNullColumnHasValue;
	}

	/**
	 * 得到内嵌结果集
	 * 
	 * @param rs
	 *            结果集
	 * @param nestedResultMapId
	 *            内嵌结果MapID
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix)
			throws SQLException {
		ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
		return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
	}

	//
	// UNIQUE RESULT KEY（唯一结果key）
	//
	/**
	 * 创建行的key
	 * 
	 * @param resultMap
	 *            结果映射
	 * @param rsw
	 *            Set结果集包装器
	 * @param columnPrefix
	 *            列前缀
	 * @return
	 * @throws SQLException
	 */
	private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
		final CacheKey cacheKey = new CacheKey();
		cacheKey.update(resultMap.getId());
		List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
		if (resultMappings.size() == 0) {
			if (Map.class.isAssignableFrom(resultMap.getType())) {
				createRowKeyForMap(rsw, cacheKey);
			} else {
				createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
			}
		} else {
			createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
		}
		return cacheKey;
	}

	/**
	 * 组合key
	 * 
	 * @param rowKey 行key
	 * @param parentRowKey 父级行key
	 * @return
	 */
	private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {
		if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {
			CacheKey combinedKey;
			try {
				combinedKey = rowKey.clone();
			} catch (CloneNotSupportedException e) {
				throw new ExecutorException("Error cloning cache key.  Cause: " + e, e);
			}
			combinedKey.update(parentRowKey);
			return combinedKey;
		}
		return CacheKey.NULL_CACHE_KEY;
	}
	/** 
	 * 通过行key得到结果映射
	 * @param resultMap 结果集
	 * @return
	 */
	private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
		List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
		if (resultMappings.size() == 0) {
			resultMappings = resultMap.getPropertyResultMappings();
		}
		return resultMappings;
	}
	/**
	 * 创建
	 * @param resultMap 结果集
	 * @param rsw  Set结果集包装器
	 * @param cacheKey 缓存key 
	 * @param resultMappings 结果映射集
	 * @param columnPrefix 列前缀
	 * @throws SQLException
	 */
	private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey,
			List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
		for (ResultMapping resultMapping : resultMappings) {
			if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {
				// Issue #392
				final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
				createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey,
						nestedResultMap.getConstructorResultMappings(),
						prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
			} else if (resultMapping.getNestedQueryId() == null) {
				final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
				final TypeHandler<?> th = resultMapping.getTypeHandler();
				List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
				// Issue #114
				if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
					final Object value = th.getResult(rsw.getResultSet(), column);
					if (value != null) {
						cacheKey.update(column);
						cacheKey.update(value);
					}
				}
			}
		}
	}
	/**
	 * 为非映射的属性创建行key
	 * @param resultMap 结果集
	 * @param rsw  Set结果集包装器
	 * @param cacheKey 缓存key 
	 * @param columnPrefix  列前缀
	 * @throws SQLException
	 */
	private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey,
			String columnPrefix) throws SQLException {
		final MetaClass metaType = MetaClass.forClass(resultMap.getType());
		List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
		for (String column : unmappedColumnNames) {
			String property = column;
			if (columnPrefix != null && !columnPrefix.isEmpty()) {
				// When columnPrefix is specified, ignore columns without the
				// prefix.
				if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
					property = column.substring(columnPrefix.length());
				} else {
					continue;
				}
			}
			if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
				String value = rsw.getResultSet().getString(column);
				if (value != null) {
					cacheKey.update(column);
					cacheKey.update(value);
				}
			}
		}
	}
	/**
	 * 为Map创建行key
	 * @param rsw  列前缀
	 * @param cacheKey 缓存key
	 * @throws SQLException
	 */
	private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
		List<String> columnNames = rsw.getColumnNames();
		for (String columnName : columnNames) {
			final String value = rsw.getResultSet().getString(columnName);
			if (value != null) {
				cacheKey.update(columnName);
				cacheKey.update(value);
			}
		}
	}

}
